import Config from "./Config";
import GameUtil from "./GameUtil";
import { IGameData, IGuestData, ILevelData } from "./IMessage";
import ItemGroup from "./ItemGroup";
import ItemGuest from "./ItemGuest";
import ItemIcon from "./ItemIcon";
import StorageUtil from "./StorageUtil";

const { ccclass, property } = cc._decorator;

export const MAX_GROUP: number = 9;
export const REMOVE_NUM: number = 3;
export const TEMP_NUM: number = 6;
export const MAX_GUEST: number = 4;
export const UNLOCK_NUM: number = 2;

export enum EItemType {
    Fly,
    Item,
    Temp,
    Test,
    Guest,
}

export enum EFlyType {
    Item,
    Progress,
}

@ccclass
export default class SceneGame extends cc.Component {
    public static instance: SceneGame = null;

    @property({ type: cc.Prefab, tooltip: "单元组预制体" })
    private itemGroup: cc.Prefab = null;
    @property({ type: cc.Prefab, tooltip: "顾客预制体" })
    private itemGuest: cc.Prefab = null;
    @property({ type: cc.Prefab, tooltip: "物品预制体" })
    private itemIcon: cc.Prefab = null;

    
    @property({ type: sp.Skeleton, tooltip: "称动画" })
    private chengSke: sp.Skeleton = null;

    @property({ type: cc.Node, tooltip: "组节点" })
    private group: cc.Node = null;
    @property({ type: cc.Node, tooltip: "顾客节点" })
    private guest: cc.Node = null;
    @property({ type: cc.Node, tooltip: "暂存节点" })
    private temp: cc.Node = null;
    @property({ type: cc.Node, tooltip: "飞" })
    private flyItem: cc.Node = null;

    @property({ type: cc.Node, tooltip: "弹窗" })
    private panel: cc.Node = null;
    @property({ type: cc.Label, tooltip: "弹窗-标题" })
    private labTitle: cc.Label = null;
    @property({ type: cc.Label, tooltip: "弹窗-输入框提示" })
    private labTip: cc.Label = null;
    @property({ type: [cc.EditBox], tooltip: "弹窗-输入框" })
    private edits: cc.EditBox[] = [];
    @property({ type: cc.Node, tooltip: "复活" })
    private btnFuhuo: cc.Node = null;
    @property({ type: cc.Node, tooltip: "关闭" })
    private btnClose: cc.Node = null;

    @property({ type: cc.Node, tooltip: "查看物品弹窗" })
    private itemPanel: cc.Node = null;

    @property({ type: cc.Node, tooltip: "游戏层遮罩" })
    private block: cc.Node = null;

    @property({ type: cc.Node, tooltip: "进度条节点" })
    private progress: cc.Node = null;
    @property({ type: cc.Label, tooltip: "关卡节点" })
    private labLevel: cc.Label = null;

    private groupNodes: cc.Node[] = [];
    private guestNodes: cc.Node[] = [];
    private tempNodes: cc.Node[] = [];

    // 未使用id数组(打乱数组时用)
    private unuseIds: number[] = [];

    private isGameEnd: boolean = false;
    private gameData: IGameData = null;

    private _data: ILevelData = null;
    public get data() {
        return this._data;
    }

    protected async onLoad() {
        SceneGame.instance = this;

        // 读取存储数据
        this.getGameData();
        // 初始化配置
        await Config.instance.init();
        await this.initData();

        this.lookItem();

        cc.tween(this.node).repeatForever(
            cc.sequence(
                cc.delayTime(3),
                cc.callFunc(() => {
                    StorageUtil.instance.write(this.gameData);
                }),
            )
        ).start();
    }

    private getGameData() {
        this.gameData = StorageUtil.instance.read();
        console.log("this.gameData:", this.gameData);
    }

    private async initData() {
        const levelData = await Config.instance.getLevelConfigById(this.gameData.level);
        if (!levelData) {
            return;
        }
        this._data = { total: levelData.total, col: levelData.col, ids: levelData.itemId, counts: [] };


        this.groupNodes.forEach((o) => {
            o.destroy();
        });
        this.guestNodes.forEach((o) => {
            o.destroy();
        });
        this.tempNodes.forEach((o) => {
            o.destroy();
        });

        this.isGameEnd = false;
        this.block.active = false;
        this.panel.active = false;
        this.btnFuhuo.active = false;
        this.btnClose.active = true;
        this.labTitle.string = `暂停`;
        this.labLevel.string = `${this.gameData.level}`;

        this.edits[0].string = `${this.data.total}`;
        this.edits[1].string = `${this.data.ids.length}`;
        this.edits[2].string = `${this.data.col}`;

        // this.gameData.cellData = [];
        // this.gameData.guestData = [];
        // this.gameData.tempData = [];
        this.groupNodes = [];
        this.guestNodes = [];
        this.tempNodes = [];

        this.groupModule();
        this.guestModule();
        this.tempItemsModule();
        this.flyToProgress(null); // 初始化进度

        if (GameUtil.isTest) {
            this.labTip.node.active = false;
            this.labTip.string = `填整数1~${50}`;
        }
    }

    private lookItem() {
        this.itemPanel.active = false;
        const scroll = cc.find("root/scrollView", this.itemPanel);
        const content = cc.find("view/content", scroll);
        for (let i = 0; i < 40; i++) {
            const node = cc.instantiate(this.itemIcon);
            node.parent = content;
            node.getComponent(ItemIcon).setTestData(i, true);
        }
    }

    private groupModule() {
        const progress = this.gameData.progress;
        if (progress.max <= 0) {
            progress.max = this.data.total / REMOVE_NUM;
        }

        if (this.gameData.cellData.length === 0) {
            // 计算每种类型数量
            progress.cur = 0;
            progress.max = this.data.total / REMOVE_NUM;
            if (progress.max !== Math.floor(progress.max)) {
                console.warn("配置数量不是3的倍数!!!");
                return;
            }

            // 兼容种类
            if (progress.max < this.data.ids.length) {
                this.data.ids.length = progress.max;
            }

            // 每种物品个数
            let tempTotal = 0; // TODO 测试
            const count = progress.max / this.data.ids.length;
            for (let i = 0; i < this.data.ids.length; i++) {
                const much = Math.ceil(count) * REMOVE_NUM;
                const less = Math.floor(count) * REMOVE_NUM;
                this.data.counts.push(i < progress.max % this.data.ids.length ? much : less);
                tempTotal += this.data.counts[i];
            }
            console.log(`总数:${this.data.total}-${tempTotal}-----种类:${this.data.counts}`);

            // 计算单元深度(每列个数)
            const totalGroup = this.data.col * MAX_GROUP;
            const cellCol = this.data.total / totalGroup;
            this.unuseIds = [];
            for (let i = 0; i < totalGroup; i++) {
                this.unuseIds.push(i);
            }
            for (let i = 0; i < totalGroup; i++) {
                this.setItemData(i >= this.data.total % totalGroup ? Math.floor(cellCol) : Math.ceil(cellCol));
            }
            // console.log("this.cellData:", this.gameData.cellData);

            // TODO 计算数量
            let tempTotal3 = 0;
            for (let i = 0; i < this.gameData.cellData.length; i++) {
                tempTotal3 += this.gameData.cellData[i].mids.length;
            }
            console.log(`总数:${this.data.total}-${tempTotal3}`);
        } else {
            this.gameData.cellData = this.gameData.cellData;
        }

        for (let i = 0; i < MAX_GROUP; i++) {
            const node = cc.instantiate(this.itemGroup);
            node.parent = this.group;
            node.getComponent(ItemGroup).setData(i);
            this.groupNodes.push(node);
        }
    }

    private guestModule() {
        if (this.gameData.guestData.length === 0) {
            for (let i = 0; i < MAX_GUEST; i++) {
                const itemId = i < UNLOCK_NUM ? this.getSpeciesId1() : -1;
                const ske = GameUtil.instance.getGuestSkeData();
                this.gameData.guestData.push({ id: i, itemId: itemId, cur: 0, max: 3, isLock: i >= UNLOCK_NUM, ske: ske });
            }
        } else {
            this.gameData.guestData = this.gameData.guestData;
        }

        for (let i = 0; i < this.gameData.guestData.length; i++) {
            const guest = this.gameData.guestData[i];
            const node = cc.instantiate(this.itemGuest);
            node.parent = this.guest;
            node.getComponent(ItemGuest).setData(guest);
            this.guestNodes.push(node);
        }

        // console.log("this.guestData:", this.gameData.guestData);
    }

    private tempItemsModule() {
        if (this.gameData.tempData.length === 0) {
            for (let i = 0; i < TEMP_NUM; i++) {
                this.gameData.tempData.push(-1);
            }
        } else {
            this.gameData.tempData = this.gameData.tempData;
        }
        // console.log("this.tempData:", this.gameData.tempData);


        // 更新暂存区初始UI
        const posX = [25, 132, 235, 330, 443, 550];
        for (let i = 0; i < this.gameData.tempData.length; i++) {
            const node = cc.instantiate(this.itemIcon);
            node.parent = this.temp;
            node.x = posX[i];
            node.getComponent(ItemIcon).setTempData({ tempId: i, itemId: this.gameData.tempData[i] }, -1);
            this.tempNodes.push(node);
        }
    }

    /**
     * 暂存区到顾客气泡
     * @param itemId 
     */
    public tempToGuest(itemId: number) {
        if (this.isGameEnd) {
            return;
        }

        this.gameData.tempData.forEach((o, i) => {
            if (o === itemId) {
                const from = this.tempNodes[i];
                this.flyItemIcon(EItemType.Temp, from, itemId);
                this.gameData.tempData[i] = -1;
                this.tempNodes[i].getComponent(ItemIcon).setTempData({ tempId: i, itemId: this.gameData.tempData[i] }, -1);
            }
        });
    }

    /**
     * 点顾客气泡触发提示动画
     * @param id 
     */
    public shakeTip(id: number) {
        this.groupNodes.forEach((o) => {
            o.getComponent(ItemGroup).shakeTip(id);
        });
    }

    /** 清空暂存 放回池子 */
    private cleanTempArea() {
        // const arr = [];
        // for (let i = 0; i < this.cellData.length; i++) {
        //     const data = this.cellData[i];
        //     if (data.curDeep < data.mids.length - 1) {
        //         arr.push(i);
        //     }
        // }

        for (let i = 0; i < this.gameData.tempData.length; i++) {
            const id = this.gameData.tempData[i];
            if (id != -1) {
                // const index = arr[Math.floor(Math.random() * arr.length)];
                // const index = 0;
                const index = Math.floor(Math.random() * this.gameData.cellData.length);
                this.gameData.cellData[index].mids.push(id);
                this.refreshGroup(this.gameData.cellData[index].gid, this.gameData.cellData[index].col, false);
            }
            this.gameData.tempData[i] = -1;
            this.tempNodes[i].getComponent(ItemIcon).setTempData({ tempId: i, itemId: -1 }, -1);
        }
    }

    /** 直接取货 */
    private guestGo() {
        const guests: IGuestData[] = [];
        for (let i = 0; i < this.gameData.guestData.length; i++) {
            const guest = this.guestNodes[i].getComponent(ItemGuest);
            // 非移动中&已解锁
            if (!guest.getIsMove() && this.gameData.guestData[i].itemId != -1) {
                guests.push(this.gameData.guestData[i]);
            }
        }
        if (guests.length <= 0) {
            // console.log("游客不存在:", guests);
            return;
        }

        // 顾客中随机一个直接走
        const index = Math.floor(Math.random() * guests.length);
        const guest = guests[index];
        const cellIds: number[] = [];
        for (let i = 0; i < this.gameData.cellData.length; i++) {
            const cell = this.gameData.cellData[i];
            for (let k = cell.curDeep; k < cell.mids.length; k++) {
                if (guest.itemId === cell.mids[k]) {
                    cellIds.push(cell.id);
                }
            }
        }

        // console.log('cellIds:', cellIds);

        if (cellIds.length <= 0) {
            return;
        }

        // 含有id的池子中取(顾客需求数-顾客已有数)个
        const ids = cellIds.sort(() => { return 0.5 - Math.random(); });
        const count = guest.max - guest.cur;
        for (let i = 0; i < count; i++) {
            const cell = this.getCellDataById(ids[i]);
            if (cell) {
                for (let k = cell.curDeep; k < cell.mids.length; k++) {
                    if (cell.mids[k] === guest.itemId) {
                        const from = this.groupNodes[cell.gid];
                        this.flyItemIcon(null, from, guest.itemId);
                        cell.mids.splice(k, 1);
                        this.refreshGroup(cell.gid, cell.col, false);
                        break;
                    }
                }
            }
        }
    }

    /**
     * 检查游戏是否结束
     */
    public checkGameResult(cb?: Function) {
        if (this.isGameEnd) {
            return;
        }

        const fail = () => {
            for (let i = 0; i < this.gameData.tempData.length; i++) {
                if (this.gameData.tempData[i] === -1) {
                    return false;
                }
            }
            return true;
        }

        const success = () => {
            let isSuccess = true;
            for (let i = 0; i < this.groupNodes.length; i++) {
                const group = this.groupNodes[i];
                for (let k = 0; k < group.children.length; k++) {
                    const node = group.children[k].children[1];
                    if (node && node.active) {
                        isSuccess = false;
                        break;
                    }
                }
            }

            for (let i = 0; i < this.gameData.tempData.length; i++) {
                if (this.gameData.tempData[i] != -1) {
                    isSuccess = false;
                    break;
                }
            }
            return isSuccess;
        }

        if (fail()) {
            console.log("游戏失败~");

            this.isGameEnd = true;
            this.block.active = true;
            setTimeout(() => {
                this.block.active = false;
                this.labTitle.string = `游戏失败`;
                this.panel.active = true;
                this.btnFuhuo.active = true;
                this.btnClose.active = false;
                cb && cb();
            }, 2000);
        } else if (success()) {
            console.log("游戏过关~");

            // this._data.level++;
            // const data: IGameData = {
            //     cellData: this.cellData,
            //     tempData: this.tempData,
            //     guestData: this.guestData,
            //     level: this._data.level,
            // }
            // StorageUtil.instance.write(data);

            this.gameData.level++
            this.gameData = {
                level: this.gameData.level,
                progress: { cur: 0, max: 0 },

                cellData: [],
                tempData: [],
                guestData: [],
            }
            StorageUtil.instance.write(this.gameData);

            this.isGameEnd = true;
            this.block.active = true;
            setTimeout(() => {
                this.block.active = false;
                this.initData();
            }, 2000);
        }
    }

    /**
     * 根据权重获取id
     * @returns 
     */
    private getSpeciesId() {
        let p = Math.random();
        let temp = 0;
        let total = 0;
        this.data.counts.forEach((o) => {
            total += o;
        });

        for (let i = 0; i < this.data.counts.length; i++) {
            temp += this.data.counts[i] / total;
            if (temp >= p) {
                this.data.counts[i]--;
                // console.log("随机index:", i);
                // console.log("数组:", this.data.counts);
                return i;
            }
        }
    }

    /**
     * 根据权重获取id
     * @returns 
     */
    public getSpeciesId1() {
        const arr = [];
        // 把池子中不为空的数据放进数组
        this.gameData.cellData.forEach((o) => {
            o.mids.forEach((o1) => {
                if (o1 != -1) arr.push(o1);
            });
        });
        // 把暂存区不为空的数据放进数组
        this.gameData.tempData.forEach((o) => {
            if (o != -1) {
                arr.push(o);
            }
        });
        // 排除已经展示的顾客需求
        if (this.gameData.guestData) {
            for (let i = arr.length - 1; i > -1; i--) {
                for (let k = 0; k < this.gameData.guestData.length; k++) {
                    if (this.gameData.guestData[k].itemId !== -1 && arr[i] === this.gameData.guestData[k].itemId) {
                        arr.splice(i, 1);
                    }
                }
            }
        }

        if (arr.length == 0) {
            return null;
        }

        const index = Math.floor(Math.random() * arr.length);
        return arr[index];
    }

    /**
     * 设置单元数据
     * @param id 
     * @param row 深度
     */
    private setItemData(row: number) {
        // 打乱数组顺序，实现随机位置创建
        const id = this.unuseIds[Math.floor(Math.random() * this.unuseIds.length)];
        this.unuseIds = GameUtil.instance.minus(this.unuseIds, [id]);
        // console.log(id, this.notSetItemIds);

        const data = {
            gid: Math.floor(id / this._data.col),
            id: id,
            col: id % this._data.col,
            curDeep: 0,
            mids: [],
        };
        for (let k = 0; k < row; k++) {
            data.mids.push(this.getSpeciesId());
        }
        this.gameData.cellData.push(data);
    }

    /**
     * 刷新组中对应位置item
     * @param gid 
     * @param col 
     */
    public refreshGroup(gid: number, col: number, isMove: boolean) {
        const group = this.groupNodes[gid];
        if (group) {
            const cla = group.getComponent(ItemGroup);
            cla.refresh(col, isMove);
        } else {
            console.log(`组${gid}不存在!!!`);
        }
    }

    public chengAnim() {
        let count = 0;
        for (let i = 0; i < this.gameData.tempData.length; i++) {
            if (this.gameData.tempData[i] !== -1) {
                count++;
            }
        }
        if (count >= 5) {
            this.chengSke.setAnimation(0, "chaozhong", true);
        } else {
            this.chengSke.setAnimation(0, "fang", false)
            this.chengSke.setCompleteListener((trackEntry, loopCount) => {
                if (trackEntry.animation.name === "fang") {
                    this.chengSke.setAnimation(0, "daiji", false);
                }
            });
        }
    }

    public flyItemIcon(type: EItemType, from: cc.Node, itemId: number) {
        const flyToTemp = () => {
            // 往暂存区域飞
            for (let i = 0; i < this.gameData.tempData.length; i++) {
                if (this.gameData.tempData[i] === -1) {
                    this.gameData.tempData[i] = itemId;
                    const cb = () => {
                        this.tempNodes[i].getComponent(ItemIcon).setTempData({ tempId: i, itemId: itemId }, -1);
                        this.chengAnim();
                        // 结束检测
                        SceneGame.instance.checkGameResult();
                    }

                    if (from) {
                        this.addItemIcon(from, this.tempNodes[i], EFlyType.Item, itemId, cb);
                    } else {
                        cb && cb();
                    }
                    break;
                }
            }
        }

        const pos = this.getGuestPosByItemId(itemId);
        if (pos != -1) {
            const guest = this.guestNodes[pos].getComponent(ItemGuest);
            // 往顾客位置飞
            if (!guest.getIsMove()) {
                const to = guest.getFlyToNode();
                if (to) {
                    this.addItemIcon(from, to, EFlyType.Item, itemId, () => {
                        if (type === EItemType.Temp) {
                            this.chengAnim();
                        }
                        guest.refreshUI();
                    });
                    // this.refreshGroup(cellData.gid, cellData.col, itemId);
                } else {
                    flyToTemp();
                }
            } else {
                flyToTemp();
            }
        } else {
            flyToTemp();
        }
    }

    public flyToProgress(from: cc.Node, itemId?: number) {
        const cb = () => {
            const progress = this.gameData.progress;
            const bar = cc.find("bar", this.progress).getComponent(cc.Sprite);
            const lab = cc.find("lab", this.progress).getComponent(cc.Label);
            const light = cc.find("light", this.progress);
            if (from) {
                progress.cur++;
            } else {
                // progress.cur = 0;
                bar.fillRange = 0;
                light.angle = 0;
            }
            bar.fillRange = progress.cur / progress.max;
            lab.string = `${Math.floor(bar.fillRange * 100)}%`;
            // light.angle = Math.floor(bar.fillRange * 100);
            cc.tween(light).to(0.15, { angle: -bar.fillRange * 360 }).start();
        }

        if (from) {
            this.addItemIcon(from, this.progress, EFlyType.Progress, itemId, cb);
        } else {
            cb && cb();
        }
    }

    /**
     * 根据物品id获取顾客节点
     * @param itemId 
     * @returns 
     */
    public getGuestPosByItemId(itemId: number) {
        for (let i = 0; i < this.gameData.guestData.length; i++) {
            const guest = this.gameData.guestData[i];
            if (guest.itemId === itemId) {
                return i;
            }
        }
        return -1;
    }

    public getGuestDataByItemId(itemId: number) {
        for (let i = 0; i < this.gameData.guestData.length; i++) {
            const guest = this.gameData.guestData[i];
            if (guest.itemId === itemId) {
                return guest;
            }
        }
        return null;
    }


    /**
     * 根据组gid获取数据
     * @param gid 
     * @returns
     */
    public getItemDataByGid(gid: number) {
        const data = this.gameData.cellData.filter((o) => o.gid === gid);
        return data;
    }

    public getCellDataById(id: number) {
        const data = this.gameData.cellData.find((o) => o.id === id);
        return data;
    }

    public getGuestDataById(id: number) {
        const data = this.gameData.guestData[id];//.find((o) => o.id === id);
        return data;
    }

    public getGuestDatas() {
        return this.gameData.guestData;
    }

    /**
     * 局部坐标转世界坐标
     * @param node 
     * @returns 
     */
    public localToGlobal(node: cc.Node) {
        const pos = node.convertToWorldSpaceAR(cc.v2(0, 0));
        return pos;
    }

    private addItemIcon(from: cc.Node, to: cc.Node, type: EFlyType, itemId: number, cb?: Function) {
        const temp = this.flyItem.children[type];
        const node = cc.instantiate(temp);
        node.parent = this.flyItem;
        node.active = true;

        const fly = () => {
            const cover1 = this.localToGlobal(from);
            const cover2 = this.localToGlobal(to);
            node.setPosition(cc.v2(cover1.x, cover1.y));
            node.stopAllActions();
            cc.tween(node).sequence(
                cc.moveTo(0.5, cover2),
                cc.callFunc(() => {
                    node.destroy();
                    cb && cb();
                }),
            ).start();
        }

        const sprite = cc.find("sprite", node).getComponent(cc.Sprite);
        GameUtil.instance.setItemIcon(EItemType.Fly, itemId, sprite, 70, 120, fly);

        if (GameUtil.isTest) {
            const lab = cc.find("id", node);
            if (lab) {
                const realId = this.data.ids[itemId];
                lab.getComponent(cc.Label).string = `${realId}`;
            }
        }
    }

    private onEditHandler(event: cc.EditBox) {
        const name = event.node.parent.name;
        switch (name) {
            case "level":
                {
                    this.gameData.level = Number(event.string) || 1;
                }
                break;
            // case "total":
            //     {
            //         this.data.total = Number(event.string);
            //     }
            //     break;
            // case "species":
            //     {
            //         // this.data.ids.length = Number(event.string);
            //     }
            //     break;
            // case "col":
            //     {
            //         this.data.col = Number(event.string);
            //     }
            //     break;
        }
    }

    private onBtnClicked(event: cc.Event, data: cc.Event.EventCustom) {
        const name = event.target.name;
        switch (name) {
            case "btnStop":
                {
                    this.panel.active = true;
                }
                break;
            case "btnGo":
                {
                    this.guestGo();
                }
                break;
            case "btnClean":
                {
                    this.cleanTempArea();
                }
                break;
            case "btnFuhuo":
                {
                    this.panel.active = false;
                    this.cleanTempArea();
                }
                break;
            case "btnRestart":
                {
                    this.initData();
                }
                break;
            case "btnClose":
                {
                    this.panel.active = false;
                }
                break;
            case "btnLook":
                {
                    this.panel.active = false;
                    this.itemPanel.active = true;
                }
                break;
            case "btnLookBack":
                {
                    this.panel.active = true;
                    this.itemPanel.active = false;
                }
                break;
        }
        console.log("按钮:", name);
    }
}